Terraform 1.10がGAになり、Ephemeral Valuesが使えるようになりました

Terraform 1.10がGAになり、Ephemeral Valuesが使えるようになりました

ephemeral 一生タイポしてまう
Clock Icon2024.12.04

2024/11/27にTerraformのVersion 1.10がGAになりました!

1.10より Ephemeral valuesという機能が利用可能になりました。この新機能の詳細を見ていきましょう。

概要

ざっくりとは、機密情報をTerraformで扱う際に利用する機能です。

例えばデータベースインスタンスをTerraformで管理しようとした場合、そのパスワード(=機密情報)の値は他のattributeと同様TerraformのStateファイルに保存されます。また terraform planコマンドに -out オプションをつけると生成されるplanファイルにも保存されます。

これらStateファイルやplanファイルが万が一外部に漏洩した場合、それはデータベースパスワードが漏洩したことになり、大きなセキュリティリスクです。

そのため従来はこのリスクの対策として、例えばリソース作成した後にTerraform外でパスワード値を更新し、パスワードattributeをignore_changes に指定するといった方法がありました。

今回登場したEphemeral valuesがこのセキュリティリスクを緩和します。Ephemeral valuesは、Stateファイル・planファイルに 保存されない 値です。

Ephemeral valuesは以下の5機能に分割できます。

  • Ephemeral input variables
  • Ephemeral output variables
  • Ephemeral resources
  • ephemeralasnull 関数
  • write-only attribute
    • write-only attributeは 次Version 1.11 でリリース予定です。 1.10には含まれていません。

それぞれ説明します。

Ephemeral input variables

variableブロックにephemeral attributeが追加されました。

variable "hoge" {
  type      = string
  ephemeral = true
}

ephemeral = trueと設定されたvariableは、現在のオペレーション(現在のterraform planもしくはterraform applyの実行のことだと思われます)でのみ使用され、Stateファイルやplanファイルには記録されません。

この ephemeral variable(=ephemeral = trueと設定されたvariable)は参照できる場所が以下に限られています。

  • 他の ephemeral variable
    • v1.9より、variableのvalidationブロック内で他のvariableを参照できるようになりました。 (参考)
      そこで使うことを想定していると思われます。
  • local value
    • ephemeral variableを参照したlocal value も自動的に ephemeral value扱いになります。つまりここのリストに書かれているものからしか参照できなくなります。
  • ephemeral resource (後述)
  • ephemeral output (後述)

要は参照先もephemeralである必要があるということですね。これ以外で参照しようとするとエラーになります。

他の箇所で参照しようとした例
variable "test-ephemeral" {
  type      = string
  default   = "test"
  ephemeral = true
}

resource "aws_s3_bucket" "main" {
  bucket_prefix = var.test-ephemeral
}
terraform plan実行結果
% terraform plan
╷
│ Error: Invalid use of ephemeral value
│ 
│   with aws_s3_bucket.main,
│   on main.tf line 2, in resource "aws_s3_bucket" "main":
│    2:   bucket_prefix = var.test-ephemeral
│ 
│ Ephemeral values are not valid in resource arguments, because resource instances must persist between Terraform phases.

Ephemeral output variables

variableブロック同様にoutputブロックにもephemeral attributeが追加されました。

output "fuga" {
  value       = aws_secretsmanager_secret.secret_id
  ephemeral   = true
}

このephemeral attributeは、child module のアウトプットでのみ使用できます。
root モジュールのoutputには使えません。

以下はroot モジュールのoutputで使ってみた例です。エラーになります。

output "test" {
  value     = "test"
  ephemeral = true
}
terraform plan実行結果
% terraform plan
│ 
│ Error: Ephemeral output not allowed
│ 
│   on outputs.tf line 1:
│    1: output "test" {
│ 
│ Ephemeral outputs are not allowed in context of a root module

エラーになるのは理にかなっています。root モジュールでoutputにするということは、terraform_remote_state データソースを使って参照するような用途が想定されます。terraform_remote_state データソースで使うにはStateファイルに値を記録する必要があり、これはephemeral valuesのコンセプトから外れます。

また、ephemeral variableと同様、ephemeral outputも参照できる箇所が限られています。

  • ephemeral resource (後述)
  • ephemeral variable
  • 他のchild moduleのephemeral output

Ephemeral resources

ephemeral valuesの本丸です。ephemeral variableもephemeral outputもこのephemeral リソースと連携することを想定しているので。

ephemeralブロックが追加されました。こちらのブロックでephemeral リソースを定義します。中に定義する内容は従来のresourceブロックとほぼ同じです。

ephemeral "<resource_type>" "<resource_name>" {
  <attributes>
  <meta-arguments>
}

また、ephemeral リソースのattributesも variableやoutputと同様参照できる箇所が限られています。

  • 他のephemeral リソース
  • local values (ephemeral value扱いになる)
  • ephemeral variable
  • ephemeral output
  • provider block(プロバイダーの設定)
  • provisionerconnection block

ephemeral リソース使用例が以下です。aws_secretsmanager_secret_versionがephemeralリソースですね。従来だとこの部分は aws_secretsmanager_secret_versionデータソースでやっていたと思うのですが、その場合その中身がStateファイルやplanファイルに記録されてしまっておりました。

provider "aws" {
  region = "eu-west-2"
}
 
data "aws_db_instance" "example" {
  db_instance_identifier = "testdbinstance"
}
 
ephemeral "aws_secretsmanager_secret_version" "db_master" {
  secret_id = data.aws_db_instance.example.master_user_secret[0].secret_arn
}
 
locals {
  credentials = jsondecode(ephemeral.aws_secretsmanager_secret.db_master.secret_string)
}
 
provider "postgresql" {
  host     = data.aws_db_instance.example.address
  port     = data.aws_db_instance.example.port
  username = local.credentials["username"]
  password = local.credentials["password"]
}
 
resource "postgresql_database" "db" {
  name = "new_db"
}

AWS providerのEphemeral resources

AWS Proverのv5.77.0でこれらEphemeral resourcesが追加されています。ですのでTerraform本体のバージョンを1.10にしたうえで、AWS Providerのバージョンも5.77.0以上に上げましょう。

aws_secretsmanager_secret_version

Secrets Manager secretの特定のversionを取得するephemeralリソースです。secretのvalueをsecret_stringに持ちます。

こちらが一番使用されるephemeralリソースになるのではないかと思います。

aws_kms_secrets

KMSで暗​​号化されたデータから複数のシークレットを復号化するephemeralリソースです。

使用方法は既存の aws_kms_secrets データソース と同じのようです。Stateファイルやplanファイルに記録されない分、今後はephemeral版の使用を第一に検討しましょう。

aws_lambda_invocation

Lambda関数の実行を行なうリソースです。

ユースケースが思い浮かばなかったのですが、上記ドキュメントに記載がありました。

The aws_lambda_invocation ephemeral resource invokes the function during every plan and apply when the function is known. A common use case for this functionality is when invoking a lightweight function—where repeated invocations are acceptable—that produces sensitive information you do not want to store in the state.

毎planとapplyでLambda関数が実行されるんですね。外部から機密情報をLambda関数経由で取得して、結果をSecrets Manager secretに登録する、みたいな用途で使われるのでしょうか。

ちなみに、ephemeralじゃないaws_lambda_invocation リソースの関数実行タイミングは、triggersを設定していない限りはapplyで当該リソースが作成された際と、 replaceが発生する際のみです。関数実行タイミングが違うので注意です。

ephemeralasnull 関数

ephemeral as null ということで、ephemeral valueをnull値に変換する関数です。

「いつ使うんや?」と思いましたが、ephemeralasnull 関数のドキュメントページでは以下ユースケースが紹介されていました。

variable "session_token" {
  type      = string
  default   = "test"
  ephemeral = true
}

variable "configuration" {
  type = map(string)
  default = {
    "env" = "development"
  }
}

# This is a contrived example, but this pattern works with any object that is a mix of ephemeral and non-ephemeral values. 
locals {
  configuration_with_token = merge(
    var.configuration,
    { "session_token" = var.session_token }
  )
}

output "configuration_settings" {
# Using ephemeralasnull enables you to output the non-ephemeral values.
  value       = ephemeralasnull(local.configuration_with_token)
  description = "Environment setting."
}

要は、ephemeral valueを含むvalueを非 ephemeral valueで参照したい場合です。
これまで説明したとおり、ephemeral value は参照できる箇所が限られています。 ephemeralasnull関数を通すことで、その参照可能箇所外でも参照できるようになります。ただしephemeral value値はnullに変換されます。

上記コードをapplyした後のoutputは以下になります。

% terraform output
configuration_settings = {
  "env" = "development"
  "session_token" = tostring(null)
}

session_tokenは ephemeral variable である session_tokenを参照しているのでephemeral valueであり、configuration_settings 全体が ephemeral value扱いになります。ですので、configuration_settings outputに ephemeral = trueを付与する必要がありますし、もしこれがrootモジュールなのであればそれでも「root モジュールのoutputはephemeral化できない」という制約に引っかかりエラーになります。ephemeralasnull関数を通すことでこの問題を回避しています。

まだ 1.10へのアップグレードは待ったほうがいいかも

https://x.com/minamijoyo/status/1861939464886780414

2024/12/04時点で 1.10のタグのついたissueは全てクローズになっています。これらの修正が盛り込まれた 1.10.1リリースを待つほうが良いと思います。

参考情報

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.